using System;
using System.Globalization;
using System.Runtime.InteropServices;
using PickGold.Charting;

namespace PickGold.Charting.Formulas
{
	internal class GeneralTechnicalIndicators : PriceIndicators
	{
		private void AverageTrueRange(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			if (inputValues.Length != 4)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
			}
			base.CheckNumOfValues(inputValues, 3);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 14;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			double[] numArray = new double[inputValues[0].Length - 1];
			for (int i = 1; i < inputValues[0].Length; i++)
			{
				double num2 = Math.Abs((double)(inputValues[1][i] - inputValues[2][i]));
				double num3 = Math.Abs((double)(inputValues[3][i - 1] - inputValues[1][i]));
				double num4 = Math.Abs((double)(inputValues[3][i - 1] - inputValues[2][i]));
				numArray[i - 1] = Math.Max(Math.Max(num2, num3), num4);
			}
			outputValues = new double[2][];
			outputValues[0] = new double[inputValues[0].Length - num];
			base.MovingAverage(numArray, out outputValues[1], num, false);
			for (int j = num; j < inputValues[0].Length; j++)
			{
				outputValues[0][j - num] = inputValues[0][j];
			}
		}

		private void CommodityChannelIndex(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			double[] numArray2;
			if (inputValues.Length != 4)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
			}
			base.CheckNumOfValues(inputValues, 3);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 10;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			double[] numArray = new double[inputValues[0].Length];
			for (int i = 0; i < inputValues[0].Length; i++)
			{
				numArray[i] = ((inputValues[1][i] + inputValues[2][i]) + inputValues[3][i]) / 3.0;
			}
			base.MovingAverage(numArray, out numArray2, num, false);
			double[] numArray3 = new double[numArray2.Length];
			double num3 = 0.0;
			for (int j = 0; j < numArray2.Length; j++)
			{
				num3 = 0.0;
				for (int m = j; m < (j + num); m++)
				{
					num3 += Math.Abs((double)(numArray2[j] - numArray[m]));
				}
				numArray3[j] = num3 / ((double)num);
			}
			outputValues = new double[][] { new double[numArray3.Length], new double[numArray3.Length] };
			for (int k = 0; k < numArray3.Length; k++)
			{
				outputValues[0][k] = inputValues[0][(k + num) - 1];
				outputValues[1][k] = (numArray[(k + num) - 1] - numArray2[k]) / (0.015 * numArray3[k]);
			}
		}

		private void EaseOfMovement(double[][] inputValues, out double[][] outputValues)
		{
			if (inputValues.Length != 4)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
			}
			base.CheckNumOfValues(inputValues, 3);
			outputValues = new double[][] { new double[inputValues[0].Length - 1], new double[inputValues[0].Length - 1] };
			for (int i = 1; i < inputValues[0].Length; i++)
			{
				outputValues[0][i - 1] = inputValues[0][i];
				double num = ((inputValues[1][i] + inputValues[2][i]) / 2.0) - ((inputValues[1][i - 1] + inputValues[2][i - 1]) / 2.0);
				double num2 = inputValues[3][i] / (inputValues[1][i] - inputValues[2][i]);
				outputValues[1][i - 1] = num / num2;
			}
		}

		public override void Formula(string formulaName, double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList, out string[][] outLabels)
		{
			outputValues = null;
			string name = formulaName.ToUpper(CultureInfo.InvariantCulture);
			outLabels = null;
			try
			{
				switch (name)
				{
					case "STANDARDDEVIATION":
						this.StandardDeviation(inputValues, out outputValues, parameterList, extraParameterList);
						return;

					case "AVERAGETRUERANGE":
						this.AverageTrueRange(inputValues, out outputValues, parameterList);
						return;

					case "EASEOFMOVEMENT":
						this.EaseOfMovement(inputValues, out outputValues);
						return;

					case "MASSINDEX":
						this.MassIndex(inputValues, out outputValues, parameterList);
						return;

					case "PERFORMANCE":
						this.Performance(inputValues, out outputValues);
						return;

					case "RATEOFCHANGE":
						this.RateOfChange(inputValues, out outputValues, parameterList);
						return;

					case "RELATIVESTRENGTHINDEX":
						this.RelativeStrengthIndex(inputValues, out outputValues, parameterList);
						return;

					case "TRIPLEEXPONENTIALMOVINGAVERAGE":
						this.Trix(inputValues, out outputValues, parameterList);
						return;

					case "MOVINGAVERAGECONVERGENCEDIVERGENCE":
						this.Macd(inputValues, out outputValues, parameterList);
						return;

					case "COMMODITYCHANNELINDEX":
						this.CommodityChannelIndex(inputValues, out outputValues, parameterList);
						return;
				}
				outputValues = null;
			}
			catch (IndexOutOfRangeException)
			{
				throw new InvalidOperationException(SR.ExceptionFormulaInvalidPeriod(name));
			}
			catch (OverflowException)
			{
				throw new InvalidOperationException(SR.ExceptionFormulaNotEnoughDataPoints(name));
			}
		}

		private void Macd(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			int num2;
			double[] numArray;
			double[] numArray2;
			if (inputValues.Length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			base.CheckNumOfValues(inputValues, 1);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 12;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodShortParameterIsNegative);
			}
			if ((parameterList.Length < 2) || !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
			{
				num2 = 0x1a;
			}
			if (num2 <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodLongParameterIsNegative);
			}
			if (num2 <= num)
			{
				throw new InvalidOperationException(SR.ExceptionIndicatorsLongPeriodLessThenShortPeriod);
			}
			base.ExponentialMovingAverage(inputValues[1], out numArray, num2, false);
			base.ExponentialMovingAverage(inputValues[1], out numArray2, num, false);
			outputValues = new double[][] { new double[(inputValues[0].Length - num2) + 1], new double[(inputValues[0].Length - num2) + 1] };
			int index = 0;
			for (int i = num2 - 1; i < inputValues[0].Length; i++)
			{
				outputValues[0][index] = inputValues[0][i];
				outputValues[1][index] = numArray2[(index + num2) - num] - numArray[index];
				index++;
			}
		}

		private void MassIndex(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			int num2;
			double[] numArray2;
			double[] numArray3;
			if (inputValues.Length != 3)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
			}
			base.CheckNumOfValues(inputValues, 2);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 0x19;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			if ((parameterList.Length < 2) || !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
			{
				num2 = 9;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodAverageParameterIsNegative);
			}
			double[] numArray = new double[inputValues[0].Length];
			for (int i = 0; i < inputValues[0].Length; i++)
			{
				numArray[i] = inputValues[1][i] - inputValues[2][i];
			}
			base.ExponentialMovingAverage(numArray, out numArray2, num2, false);
			base.ExponentialMovingAverage(numArray2, out numArray3, num2, false);
			outputValues = new double[][] { new double[(numArray3.Length - num) + 1], new double[(numArray3.Length - num) + 1] };
			int index = 0;
			double num5 = 0.0;
			for (int j = ((2 * num2) - 3) + num; j < inputValues[0].Length; j++)
			{
				outputValues[0][index] = inputValues[0][j];
				num5 = 0.0;
				for (int k = (j - num) + 1; k <= j; k++)
				{
					num5 += numArray2[(k - num2) + 1] / numArray3[(k - (2 * num2)) + 2];
				}
				outputValues[1][index] = num5;
				index++;
			}
		}

		private void Performance(double[][] inputValues, out double[][] outputValues)
		{
			if (inputValues.Length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			base.CheckNumOfValues(inputValues, 1);
			outputValues = new double[][] { new double[inputValues[0].Length], new double[inputValues[0].Length] };
			for (int i = 0; i < inputValues[0].Length; i++)
			{
				outputValues[0][i] = inputValues[0][i];
				outputValues[1][i] = ((inputValues[1][i] - inputValues[1][0]) / inputValues[1][0]) * 100.0;
			}
		}

		private void RateOfChange(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			if (inputValues.Length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			base.CheckNumOfValues(inputValues, 1);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 10;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			outputValues = new double[][] { new double[inputValues[0].Length - num], new double[inputValues[0].Length - num] };
			for (int i = num; i < inputValues[0].Length; i++)
			{
				outputValues[0][i - num] = inputValues[0][i];
				outputValues[1][i - num] = ((inputValues[1][i] - inputValues[1][i - num]) / inputValues[1][i - num]) * 100.0;
			}
		}

		private void RelativeStrengthIndex(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			if (inputValues.Length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			base.CheckNumOfValues(inputValues, 1);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 10;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			double[] numArray = new double[inputValues[0].Length - 1];
			double[] numArray2 = new double[inputValues[0].Length - 1];
			for (int i = 1; i < inputValues[0].Length; i++)
			{
				if (inputValues[1][i - 1] < inputValues[1][i])
				{
					numArray[i - 1] = inputValues[1][i] - inputValues[1][i - 1];
					numArray2[i - 1] = 0.0;
				}
				if (inputValues[1][i - 1] > inputValues[1][i])
				{
					numArray[i - 1] = 0.0;
					numArray2[i - 1] = inputValues[1][i - 1] - inputValues[1][i];
				}
			}
			double[] numArray3 = new double[inputValues[0].Length];
			double[] numArray4 = new double[inputValues[0].Length];
			base.ExponentialMovingAverage(numArray2, out numArray4, num, false);
			base.ExponentialMovingAverage(numArray, out numArray3, num, false);
			outputValues = new double[][] { new double[numArray4.Length], new double[numArray4.Length] };
			for (int j = 0; j < numArray4.Length; j++)
			{
				outputValues[0][j] = inputValues[0][j + num];
				outputValues[1][j] = 100.0 - (100.0 / (1.0 + (numArray3[j] / numArray4[j])));
			}
		}

		private void StandardDeviation(double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList)
		{
			int num2;
			int length = inputValues.Length;
			try
			{
				num2 = int.Parse(parameterList[0], CultureInfo.InvariantCulture);
			}
			catch (Exception exception)
			{
				if (exception.Message == SR.ExceptionObjectReferenceIsNull)
				{
					throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
				}
				throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + exception.Message);
			}
			if (num2 <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			bool startFromFirst = bool.Parse(extraParameterList[0]);
			if (length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			if (inputValues[0].Length != inputValues[1].Length)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
			}
			if (inputValues[0].Length < num2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
			}
			outputValues = new double[2][];
			base.StandardDeviation(inputValues[1], out outputValues[1], num2, startFromFirst);
			outputValues[0] = new double[outputValues[1].Length];
			for (int i = 0; i < outputValues[1].Length; i++)
			{
				if (startFromFirst)
				{
					outputValues[0][i] = inputValues[0][i];
				}
				else
				{
					outputValues[0][i] = inputValues[0][(i + num2) - 1];
				}
			}
		}

		private void Trix(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			double[] numArray;
			double[] numArray2;
			double[] numArray3;
			if (inputValues.Length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			base.CheckNumOfValues(inputValues, 1);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 12;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			base.ExponentialMovingAverage(inputValues[1], out numArray, num, false);
			base.ExponentialMovingAverage(numArray, out numArray2, num, false);
			base.ExponentialMovingAverage(numArray2, out numArray3, num, false);
			outputValues = new double[][] { new double[(inputValues[0].Length - (num * 3)) + 2], new double[(inputValues[0].Length - (num * 3)) + 2] };
			int index = 0;
			for (int i = (num * 3) - 2; i < inputValues[0].Length; i++)
			{
				outputValues[0][index] = inputValues[0][i];
				outputValues[1][index] = (numArray3[index + 1] - numArray3[index]) / numArray3[index];
				index++;
			}
		}

		public override string Name
		{
			get
			{
				return SR.FormulaNameGeneralTechnicalIndicators;
			}
		}
	}
}

